<?php

use Swoole\Coroutine;
require __DIR__ . '/vendor/autoload.php';

function getConfig()
{
    return json_decode(file_get_contents(__DIR__ . '/config.json'), true);
}

class WebHook
{
    /**
     * 服务器
     *
     * @var swoole_http_server
     */
    private $server;

    /**
     * 服务器监听IP
     *
     * @var string
     */
    private $ip;

    /**
     * 服务器监听端口
     *
     * @var int
     */
    private $port;

    /**
     * 任务队列长度
     *
     * @var int
     */
    private $taskMemorySize;

    public function __construct($ip, $port, $taskMemorySize)
    {
        $this->ip = $ip;
        $this->port = $port;
        $this->taskMemorySize = $taskMemorySize;
    }

    /**
     * 运行服务
     *
     * @return void
     */
    public function run()
    {
        $this->server = new swoole_http_server($this->ip, $this->port, SWOOLE_BASE);

        $config = getConfig();
        if(isset($config['server']['setting']))
        {
            $this->server->set($config['server']['setting']);
        }

        $this->server->on('request', function (swoole_http_request $request, swoole_http_response $response) {
            return $this->onRequest($request, $response);
        });

        $this->server->on('WorkerStart', function(){
            \Swoole\Runtime::enableCoroutine();
        });

        $this->server->on('task', function($serv, $task){
            go(function() use($serv, $task) {
                $this->onTask($serv, $task);
            });
        });

        unset($config);
        $this->server->start();
    }

    /**
     * 处理请求
     *
     * @param swoole_http_request $request
     * @param swoole_http_response $response
     * @return void
     */
    private function onRequest(swoole_http_request $request, swoole_http_response $response)
    {
        try{
            switch($request->server['request_uri'])
            {
                case '/gitee':
                    $this->server->task([
                        'type'  =>  'Gitee',
                        'data'  =>  $request->rawcontent(),
                        'header'=>  $request->header,
                    ]);
                    break;
                case '/github':
                    $this->server->task([
                        'type'  =>  'Github',
                        'data'  =>  $request->rawcontent(),
                        'header'=>  $request->header,
                    ]);
                    break;
                default:
                $response->write('<p>are you ok?</p>');
                    break;
            }
        } catch(\Throwable $ex) {
            $response->write($ex->getMessage());
        }
        $response->end('<p>Author: Yurun (<a href="https://gitee.com/Yurunsoft" target="_blank">Gitee</a> / <a href="https://github.com/Yurunsoft" target="_blank">Github</a>)</p>');
    }

    /**
     * 处理码云
     *
     * @param array $data
     * @return void
     */
    private function parseGitee($data)
    {
        $data['data'] = json_decode($data['data'], true);
        $config = getConfig();
        foreach($config['sites']['gitee'] as $item)
        {
            if(isset($item['name']) && $item['name'] !== $data['data']['project']['path_with_namespace'])
            {
                continue;
            }
            if(isset($item['password']) && $item['password'] !== $data['data']['password'])
            {
                continue;
            }
            if(isset($item['hook_name']) && $item['hook_name'] !== $data['data']['hook_name'])
            {
                continue;
            }
            if(isset($item['ref']) && $item['ref'] !== $data['data']['ref'])
            {
                continue;
            }
            if(!isset($item['cmds']) || !is_array($item['cmds']))
            {
                break;
            }
            foreach($item['cmds'] as $cmd)
            {
                Coroutine::exec($cmd);
            }
            echo 'gitee hook', PHP_EOL;
            return;
        }
        echo 'gitee no action', PHP_EOL;
    }

    /**
     * 处理Github
     *
     * @param array $data
     * @return void
     */
    private function parseGithub($data)
    {
        $rawData = $data['data'];
        $data['data'] = json_decode($data['data'], true);
        $config = getConfig();
        foreach($config['sites']['github'] as $item)
        {
            if(isset($item['name']) && $item['name'] !== $data['data']['repository']['full_name'])
            {
                continue;
            }
            if(isset($item['password']))
            {
                list($algo, $hash) = explode('=', $data['header']['x-hub-signature']);
                $myHash = hash_hmac($algo, $rawData, $item['password']);
                if($hash !== $myHash)
                {
                    continue;
                }
            }
            if(isset($item['hook_name']) && $item['hook_name'] !== $data['header']['x-github-event'])
            {
                continue;
            }
            if(isset($item['ref']) && $item['ref'] !== $data['data']['ref'])
            {
                continue;
            }
            if(!isset($item['cmds']) || !is_array($item['cmds']))
            {
                break;
            }
            foreach($item['cmds'] as $cmd)
            {
                Coroutine::exec($cmd);
            }
            echo 'github hook', PHP_EOL;
            return;
        }
        echo 'github no action', PHP_EOL;
    }

    private function onTask($serv, $task)
    {
        switch($task->data['type'])
        {
            case 'Gitee':
                $this->parseGitee($task->data);
                break;
            case 'Github':
                $this->parseGithub($task->data);
                break;
        }
    }

}

$config = getConfig();
$webhook = new WebHook($config['server']['host'], $config['server']['port'], $config['server']['taskMemorySize']);
unset($config);
$webhook->run();
